home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Controls / Visual Basic Controls.iso / vbcontrol / cpkocx17 / support.bas < prev    next >
Encoding:
BASIC Source File  |  1997-06-01  |  23.2 KB  |  803 lines

  1. Attribute VB_Name = "SUPPORT"
  2. '
  3. ' Support.bas
  4. '
  5. ' This file contains support functions and subroutines
  6. '
  7. ' Misc functions that didn't fit anywhere else...
  8. '
  9. Option Explicit
  10.  
  11. ' Screen.MousePointers
  12. Const HOURGLASS = 11         ' 11 - Hourglass
  13.  
  14. ' MsgBox parameters
  15. Const MB_ICONSTOP = 16       ' Critical message
  16.  
  17.  
  18. ' Application-wide variables
  19. Global App_Done As Integer
  20.  
  21.  
  22. ' ---- Net DDE support ----
  23.  
  24. ' Here are the permissions allowed for dwPermissions:
  25. Global Const NDDEACCESS_REQUEST = &H1          'Allows LinkRequest
  26. Global Const NDDEACCESS_ADVISE = &H2           'Allows LinkAdvise
  27. Global Const NDDEACCESS_POKE = &H4             'Allows LinkPoke
  28. Global Const NDDEACCESS_EXECUTE = &H8          'Allows LinkExecute
  29. Global Const NDDEACCESS_START_APP = &H10       'Starts source application on connect
  30.  
  31. Global Const MAX_NDDESHARENAME_PLUSONE = 65
  32.  
  33. Type NDDESHAREINFO
  34.     szShareName As String * MAX_NDDESHARENAME_PLUSONE
  35.     lpszTargetApp As Long    'LPSTR lpszTargetApp
  36.     lpszTargetTopic As Long  'LPSTR lpszTargetTopic
  37.     lpbPassword1 As Long     'LPBYTE lpbPassword1
  38.     cbPassword1 As Long      'DWORD  cbPassword1;
  39.     dwPermissions1 As Long   'DWORD  dwPermissions1;
  40.     lpbPassword2 As Long     'LPBYTE lpbPassword2;
  41.     cbPassword2 As Long      'DWORD  cbPassword2;
  42.     dwPermissions2  As Long  'DWORD  dwPermissions2;
  43.     lpszItem As Long         'LPSTR  lpszItem;
  44.     cAddItems As Long        'LONG   cAddItems;
  45.     lpNDdeShareItemInfo As Long
  46. End Type
  47.  
  48. #If Win16 Then
  49. Declare Function NDdeGetWindow Lib "nddeapi.DLL" () As Integer
  50. Declare Function NDdeShareAdd Lib "nddeapi.DLL" (Server As Any, ByVal level As Integer, ShareInfo As NDDESHAREINFO, ByVal nSize As Long) As Integer
  51. Declare Function NDdeShareDel Lib "nddeapi.DLL" (lpszServer As Any, ByVal lpszShareName As String, ByVal wReserved As Integer) As Integer
  52. Declare Function NDdeGetNodeName Lib "nddeapi.DLL" (ByVal lpszNodeName As String, ByVal cNodeNameLimit As Long) As Long
  53. Declare Function NDdeShareGetInfo Lib "nddeapi.DLL" (ByVal lpszServer As String, ByVal lpszShareName As String, ByVal nLevel As Integer, lpBuf As NDDESHAREINFO, ByVal cBufSz As Long, lpnTotAvail As Long, ByVal lpnItems As Integer) As Integer
  54. Declare Function NDdeGetClientInfo Lib "nddeapi.DLL" (ByVal hWndClient As Integer, ByVal lpszClientNode As String, ByVal cClientNodeLimit As Long, ByVal lpszClientApp As String, ByVal cClientAppLimit As Long) As Integer
  55.  
  56. Declare Function lstrcpy Lib "kernel" (szDest As Any, szSource As Any) As Long
  57. #Else
  58. Declare Function NDdeGetWindow Lib "nddeapi.DLL" () As Integer
  59. Declare Function NDdeShareAdd Lib "nddeapi.DLL" (Server As Any, ByVal level As Integer, ShareInfo As NDDESHAREINFO, ByVal nSize As Long) As Integer
  60. Declare Function NDdeShareDel Lib "nddeapi.DLL" (lpszServer As Any, ByVal lpszShareName As String, ByVal wReserved As Integer) As Integer
  61. Declare Function NDdeGetNodeName Lib "nddeapi.DLL" (ByVal lpszNodeName As String, ByVal cNodeNameLimit As Long) As Long
  62. Declare Function NDdeShareGetInfo Lib "nddeapi.DLL" (ByVal lpszServer As String, ByVal lpszShareName As String, ByVal nLevel As Integer, lpBuf As NDDESHAREINFO, ByVal cBufSz As Long, lpnTotAvail As Long, ByVal lpnItems As Integer) As Integer
  63. Declare Function NDdeGetClientInfo Lib "nddeapi.DLL" (ByVal hWndClient As Integer, ByVal lpszClientNode As String, ByVal cClientNodeLimit As Long, ByVal lpszClientApp As String, ByVal cClientAppLimit As Long) As Integer
  64.  
  65. Declare Function lstrcpy Lib "kernel32" Alias "lstrcpyA" (szDest As Any, szSource As Any) As Long
  66. #End If
  67.  
  68.  
  69. 'Here are the possible return values from NDdeShareAdd():
  70. Global Const NDDE_NO_ERROR = 0                 'No error.
  71. Global Const NDDE_BUF_TOO_SMALL = 2            'Buffer is too small to hold information.
  72. Global Const NDDE_INVALID_APPNAME = 13         'Application name is not valid.
  73. Global Const NDDE_INVALID_ITEMNAME = 9         'Item name is not valid.
  74. Global Const NDDE_INVALID_LEVEL = 7            'Invalid level; nLevel parameter must be 2.
  75. Global Const NDDE_INVALID_PASSWORD = 8         'Password is not valid.
  76. Global Const NDDE_INVALID_SERVER = 4           'Computer name is not valid;
  77.                                  
  78. Global Const NDDE_INVALID_SHARE = 5            'Share name is not valid.
  79. Global Const NDDE_INVALID_TOPIC = 10           'Topic name is not valid.
  80. Global Const NDDE_OUT_OF_MEMORY = 12           'Not enough memory to complete request.
  81. Global Const NDDE_ALREADY_EXISTS = 15           'Existing shares cannot be replaced.
  82.  
  83. '
  84. ' Catenate a new part (file or directory) to an
  85. ' existing file system path
  86. '
  87. Function AddPart$(Path$, Part$)
  88.     Dim c$
  89.  
  90.     ' If path not null
  91.     If Path$ <> "" Then
  92.         c$ = Mid$(Path$, Len(Path$), 1)
  93.         
  94.         If c$ <> ":" And c$ <> "\" Then
  95.             Path$ = Path$ & "\"
  96.         End If
  97.     End If
  98.  
  99.     AddPart$ = Path$ & Part$
  100.  
  101. End Function
  102.  
  103. Sub App_Close(f As Form)
  104.     Help_Close
  105.     Options_Write f
  106. End Sub
  107.  
  108. Sub App_Init(f As Form)
  109.     Help_Init
  110.  
  111.     Options_Read f
  112.     Game_Clear
  113.     
  114.     If Command$ <> "" Then
  115.         Game_Open (Command$)
  116.     End If
  117.  
  118.     App_Done = False
  119.  
  120. End Sub
  121.  
  122. '
  123. ' This function asks the user whether he wants to overwrite an
  124. ' existing file.
  125. '
  126. ' Returns IDYES, IDNO or IDCANCEL
  127. '
  128. ' In case of IDNO, the caller should re-prompt the user for a
  129. ' different file name.
  130. '
  131. Function AskOverWrite(FileName$) As Integer
  132.     Dim Msg As String
  133.  
  134.     Msg = "File '" & FileName$ & "' already exists." & Chr$(10)
  135.     Msg = Msg & "Do you want to replace it with the new file?"
  136.     
  137.     AskOverWrite = MsgBox(Msg, MB_YESNOCANCEL + MB_ICONQUESTION, App.Title)
  138. End Function
  139.  
  140. '
  141. ' Test whether the specified file exists.
  142. ' Returns True or False
  143. '
  144. Function FileExists(fname$) As Integer
  145.     Dim S$
  146.     
  147.     S$ = Dir$(fname$)
  148.     
  149.     If S$ <> "" Then
  150.         FileExists = True
  151.     Else
  152.         FileExists = False
  153.     End If
  154. End Function
  155.  
  156. '
  157. ' Extract "file.ext" part from a complex pathname,
  158. ' such as X:\foo\bar\file.ext
  159. '
  160. ' Returns the 'file part' string
  161. '
  162. Function FilePart$(P$)
  163.     Dim I As Integer, L As Integer
  164.     Dim f As String, c As String
  165.  
  166.     FilePart$ = P$
  167.     
  168.     L = Len(P$)
  169.     
  170.     ' scan the pathname backwards, stopping at
  171.     ' the first path delimiter character
  172.     For I = L To 1 Step -1
  173.         c = Mid$(P$, I, 1)
  174.         If c = ":" Or c = "\" Then
  175.             FilePart$ = Mid$(P$, I + 1)     ' return string at right side of delimiter
  176.             Exit Function
  177.         End If
  178.     Next I
  179.  
  180.  
  181. End Function
  182.  
  183. '
  184. ' This subroutine centers a form on the screen.
  185. '
  186. ' Typical use is in a Form LOAD method.
  187. '
  188. Sub Form_Center(f As Form)
  189.  
  190.     f.Left = (Screen.Width - f.Width) \ 2
  191.     f.Top = (Screen.Height - f.Height) \ 2
  192.     
  193. End Sub
  194.  
  195. Sub Form_SetTitle(f As Form)
  196.     f.Caption = App.Title & " - " & FilePart$(Game_FileName$)
  197. End Sub
  198.  
  199. '
  200. ' Close the help tool if any was open for this program
  201. '
  202. Sub Help_Close()
  203.     On Error Resume Next
  204.     WinHelp Screen.ActiveForm.hWnd, App.HelpFile, HELP_QUIT, CLng(0)
  205. End Sub
  206.  
  207. Sub Help_Conts()
  208.     WinHelp Screen.ActiveForm.hWnd, App.HelpFile, APP_HELP_CONTENTS, CLng(0)
  209. End Sub
  210.  
  211. '
  212. ' Converts a relative help file path into an
  213. ' absolute path name. This allows us to find the help
  214. ' file even if we move later on.
  215. '
  216. ' NOTE: The start-up working directory should have been set
  217. '       to the dir where the executable is located FROM THE
  218. '       WINDOWS PROGRAM MANAGER. Failure to do so will cause
  219. '       the program to start with WINDOWS as the current dir.
  220. '
  221. ' This sub should be called first thing in the program,
  222. ' that is in Sub Main() or in the first Form_Load()
  223. '
  224. Sub Help_Init()
  225.     Dim D$, f$
  226.  
  227.     D$ = CurDir$        '
  228.     f$ = App.HelpFile   ' should be a path relative to the startup dir
  229.  
  230.     ' combine the 2 paths intelligently, accounting for
  231.     ' path that climb and descend, to specify an adjacent directory.
  232.     ' e.g.:
  233.     '   start-up dir            = "C:\a\b\c"
  234.     '   rel. path to help file  = "..\..\d\x.hlp"
  235.     '   abs. path to help file  = "C:\a\d\x.hlp"
  236.  
  237.     While InStr(f$, "..\") > 0  ' path goes up
  238.         f$ = Mid$(f$, 4)        ' remove climb to parent
  239.         D$ = PathPart$(D$)      ' remove one level from current dir
  240.     Wend
  241.  
  242.     App.HelpFile = AddPart$(D$, f$)
  243. End Sub
  244.  
  245. '
  246. ' Display WinHelp search dialog
  247. '
  248. Sub Help_Search(key$)
  249.     WinHelpString Screen.ActiveForm.hWnd, App.HelpFile, HELP_PARTIALKEY, key$
  250. End Sub
  251.  
  252. '
  253. ' Open the help tool, showing a specific topic
  254. '
  255. Sub Help_Show(Topic As Integer)
  256.     WinHelp Screen.ActiveForm.hWnd, App.HelpFile, HELP_CONTEXT, CLng(Topic)
  257. End Sub
  258.  
  259. '
  260. ' Open the help tool, show the page about using the
  261. ' help system itself.
  262. '
  263. Sub Help_UsingHelp()
  264.     WinHelp Screen.ActiveForm.hWnd, App.HelpFile, HELP_HELPONHELP, CLng(0)
  265. End Sub
  266.  
  267. ' Get a whole line of text from a file, stopping at
  268. ' new line or EOF.
  269. '
  270. ' Apparently, VB does not have a variant of Input #
  271. ' that can read a whole line, up to the CR/LF
  272. ' regardless of the contains (if it can, I didn't
  273. ' find it).
  274. '
  275. Function InputLine$(f As Integer)
  276.     Dim S As String, c As String
  277.     Dim LF As String, CR As String
  278.     
  279.     CR = Chr$(13)
  280.     LF = Chr$(10)
  281.  
  282.     S = ""
  283.  
  284.     Do While Not EOF(f)
  285.         c = Input$(1, #f)
  286.         If c <> LF And c <> CR Then S = S & c
  287.         If c = CR Then Exit Do
  288.     Loop
  289.  
  290.     InputLine$ = S
  291.  
  292. End Function
  293.  
  294. '
  295. ' Returns True if char C is in set CSet
  296. '
  297. Function IsInCharSet(c As String, CSet As String) As Integer
  298.     Dim n As Integer, I As Integer
  299.  
  300.     n = Len(CSet)
  301.     IsInCharSet = False
  302.     
  303.     For I = 1 To n
  304.         If Mid$(CSet, I, 1) = c Then
  305.             IsInCharSet = True
  306.             Exit Function
  307.         End If
  308.     Next I
  309.  
  310. End Function
  311.  
  312.  
  313. Sub NDDEConnect(c As Control, Computer As String, Topic As String, Item As String)
  314.     
  315.     Dim r As Long
  316.     
  317.     'Debug.Print "NDDEConnect: trying "; Item
  318.  
  319.     ' The link topic identifies the computer name and link topic
  320.     ' as established by the DDE source application
  321.     c.LinkMode = 0      ' turn off link just in case it's up
  322.     
  323.     
  324.     
  325.     ' NOTE WELL:
  326.     ' You can debug the network game via DDE on one computer,
  327.     ' Run Copy 1, compiled as 'peer.exe', with the following line set to 'briscola|game'
  328.     ' Run Copy 2, from within VB, with the following line set to 'peer|game'
  329.     c.LinkTopic = "zot|game"
  330.     
  331.     ' c.LinkTopic = "\\" & Computer & "\" & "NDDE$" & "|" + Topic
  332.  
  333.  
  334.     c.LinkItem = Item   ' Name of text box in DDE source app
  335.     c.LinkMode = 1      ' Automatic link.
  336.     
  337.     'Debug.Print "NDDEConnect: linked "; Item
  338.  
  339. End Sub
  340.  
  341. Function NDDEListen(szShare As String, szTargetName As String, szTopic As String) As Integer
  342.       
  343.       Dim szItemName As String
  344.       Dim szReadOnlyPassword As String ' Read-only pw Net DDE share
  345.       Dim szFullAccessPassword As String ' Full access password
  346.       Dim ShareInfo As NDDESHAREINFO
  347.  
  348.  
  349. On Error GoTo nddel_err
  350.       szShare = szShare + Chr$(0)
  351.       szTargetName = szTargetName + Chr$(0)
  352.       szTopic = szTopic + Chr$(0)
  353.       szItemName = Chr$(0)                    'All items are allowed
  354.       szReadOnlyPassword = Chr$(0)            'No password
  355.       szFullAccessPassword = Chr$(0)
  356.       
  357.       'Provide the share, target, topic, and item names along with
  358.       'passwords that identify the network DDE share
  359.       ShareInfo.szShareName = szShare
  360.       ShareInfo.lpszTargetApp = lstrcpy(ByVal szTargetName, ByVal szTargetName)
  361.       ShareInfo.lpszTargetTopic = lstrcpy(ByVal szTopic, ByVal szTopic)
  362.       ShareInfo.lpszItem = lstrcpy(ByVal szItemName, ByVal szItemName)
  363.       ShareInfo.cbPassword1 = 0
  364.       ShareInfo.lpbPassword1 = lstrcpy(ByVal szReadOnlyPassword, ByVal szReadOnlyPassword)
  365.       ShareInfo.dwPermissions1 = NDDEACCESS_REQUEST Or NDDEACCESS_ADVISE Or NDDEACCESS_POKE Or NDDEACCESS_EXECUTE Or NDDEACCESS_START_APP
  366.       ShareInfo.cbPassword2 = 0
  367.       ShareInfo.lpbPassword2 = lstrcpy(ByVal szFullAccessPassword, ByVal szFullAccessPassword)
  368.       ShareInfo.dwPermissions2 = NDDEACCESS_REQUEST Or NDDEACCESS_ADVISE Or NDDEACCESS_POKE Or NDDEACCESS_EXECUTE Or NDDEACCESS_START_APP
  369.       ShareInfo.lpNDdeShareItemInfo = 15
  370.       
  371.       NDDEListen = NDdeShareAdd(ByVal 0&, 2, ShareInfo, Len(ShareInfo))
  372.       Exit Function
  373.       
  374. nddel_err:
  375.       NDDEListen = -1
  376.       Exit Function
  377.  
  378. End Function
  379.  
  380. Function NetBrowseHost$()
  381.     NetBrowseHost$ = InputBox("Enter Destination Computer", "Briscola", "")
  382. End Function
  383.  
  384. Function NetHostName$()
  385.     Dim S$, r%
  386.  
  387.     'On Error GoTo net_err
  388.     S$ = Space$(255)
  389.     r% = NDdeGetNodeName(S$, Len(S$))
  390.  
  391.     For r% = 1 To Len(S$)
  392.         If Mid$(S$, r%, 1) = Chr$(0) Then Exit For
  393.     Next r%
  394.     NetHostName$ = Left$(S$, r% - 1)
  395.     Exit Function
  396.  
  397. net_err:
  398.     
  399.     NetHostName$ = InputBox("Enter name of this Computer", "Briscola", "")
  400.     Exit Function
  401. End Function
  402.  
  403. '
  404. ' Splits string S in words, putting them in the wd_parsed()
  405. ' array. Words are delimited by "blanks", as defined
  406. ' by character set Bln.
  407. '
  408. ' The max number of words that will be stored is limited
  409. ' by the size of the wd_parsed array.
  410. '
  411. ' Returns the number of words stored.
  412. '
  413. Function Parse(S As String, Bln As String, wd_parsed() As String) As Integer
  414.     
  415.     Dim L As Integer, c As String, I As Integer
  416.     Dim wd_min As Integer, wd_max As Integer        ' bounds of the passed array
  417.     Dim wd_num As Integer                           ' words parsed so far
  418.  
  419.     Dim wd_start As Integer, wd_end As Integer      ' bounds of current word
  420.     Dim wd_len As Integer
  421.     
  422.     
  423.     
  424.     L = Len(S)
  425.     I = 1
  426.     wd_num = 0
  427.     
  428.     ' get bounds of the wd_parsed array
  429.     wd_min = LBound(wd_parsed, 1)
  430.     wd_max = UBound(wd_parsed, 1)
  431.  
  432.     Do
  433.         wd_start = 0        ' no word found
  434.         wd_end = 0
  435.         
  436.         
  437.         ' extract a word
  438.         Do
  439.             c = Mid$(S, I, 1)
  440.             
  441.             If IsInCharSet(c, Bln) = True Then      ' C is a blank
  442.                 If wd_start > 0 Then wd_end = I - 1 ' Mark word as terminated (if any)
  443.             Else                                    ' C is not a blank
  444.                 If wd_start = 0 Then wd_start = I   ' Mark start of a new word (if none)
  445.             End If
  446.             
  447.             I = I + 1
  448.  
  449.         Loop While (wd_end = 0 And I <= L)          ' until EOS or whole word retrieved
  450.  
  451.  
  452.         ' if a word was extracted, try to store it in the result array
  453.         If wd_start > 0 Then
  454.             If wd_end = 0 Then wd_end = L           ' word was unterminated:
  455.                                                     ' no trailing blanks found, take
  456.                                                     ' EOWord = EOS
  457.             wd_len = wd_end - wd_start + 1
  458.  
  459.             ' if room is left in the wd_parsed array and the word is not empty,
  460.             ' store the word in the array
  461.             If wd_len > 0 And wd_num < (wd_max - wd_min + 1) Then
  462.                 wd_parsed(wd_min + wd_num) = Mid$(S, wd_start, wd_len)
  463.                 wd_num = wd_num + 1
  464.             End If
  465.         End If
  466.  
  467.     Loop While (I <= L)                             ' continue until EOS
  468.  
  469.     Parse = wd_num                                  ' return # words stored
  470.  
  471. End Function
  472.  
  473. '
  474. ' Extract "D:\dir\dir\" part from a complex pathname
  475. '
  476. ' This function also takes care of some VB oddities,
  477. ' making sure that the returned path is legal for
  478. ' use with 'ChDir'
  479. '
  480. ' See Also 'FilePart$()'
  481. '
  482. Function PathPart$(P$)
  483.     Dim L, I As Integer
  484.     Dim c As String
  485.     Dim Pt As String
  486.  
  487.     L = Len(P$)
  488.  
  489.     
  490.     ' scan the string backwards, until a path delimiter is found
  491.     For I = L To 1 Step -1
  492.        c = Mid$(P$, I, 1)
  493.        If c = "\" Or c = ":" Then Exit For
  494.     Next I
  495.  
  496.     ' extract the 'path part' at the left of the delimiter
  497.     Pt = Left$(P$, I)
  498.  
  499.     
  500.     ' Now check for some weird path formats that
  501.     ' ChDir can and others it can't handle
  502.     L = Len(Pt)
  503.     
  504.     ' a terminal "\" is legal only for "root dir"
  505.     If L > 1 And Mid$(Pt, L, 1) = "\" Then              ' a terminal '\'
  506.         If Mid$(Pt, L - 1, 1) <> ":" Then               ' but not ':\'
  507.             Pt = Left$(Pt, L - 1)                       ' if so, kill the '\'
  508.         End If
  509.     End If
  510.  
  511.     PathPart$ = Pt
  512.  
  513. End Function
  514.  
  515. '
  516. ' Returns position of 1st occurrence of 1 char
  517. ' from character set CSset in string S, starting the scan at I
  518. '
  519. ' Almost like InStr(), but does not look for a substring,
  520. ' looks for chars in a given character set!
  521. '
  522. ' A return value of 0 means 'no char from set CSet was found in string'
  523. '
  524. ' See Also: 'PosDiff()'
  525. '
  526. Function Pos(S As String, CSet As String, I As Integer) As Integer
  527.  
  528.     Dim L As Integer, j As Integer
  529.  
  530.     L = Len(S)
  531.     Pos = 0
  532.     
  533.     If I < 1 Or I > L Then Exit Function                    ' skip obvious illegalities
  534.  
  535.     For j = I To L                                          ' For each char in string
  536.         If IsInCharSet(Mid$(S, j, 1), CSet) = True Then
  537.             Pos = j
  538.             Exit Function
  539.         End If
  540.     Next j
  541.  
  542. End Function
  543.  
  544. '
  545. ' Returns position in string S of 1st occurrence of any char
  546. ' DIFFERENT from those in set CSet, starting the scan at I
  547. '
  548. ' See Also: 'Pos()'
  549. '
  550. Function PosDiff(S As String, CSet As String, I As Integer) As Integer
  551.     Dim L As Integer, j As Integer
  552.  
  553.     L = Len(S)
  554.     PosDiff = 0
  555.     
  556.     If I < 1 Or I > L Then Exit Function                    ' purge illegal vals
  557.  
  558.     For j = I To L                                          ' For each char in string
  559.         If IsInCharSet(Mid$(S, j, 1), CSet) = False Then
  560.             PosDiff = j
  561.             Exit Function
  562.         End If
  563.     
  564.     Next j
  565.  
  566. End Function
  567.  
  568. Function Profile_ReadBool(Sect$, key$, Def%) As Integer
  569.     
  570.     Dim S$, D$
  571.  
  572.     If Def% Then
  573.         D$ = "yes"
  574.     Else
  575.         D$ = "no"
  576.     End If
  577.  
  578.     S$ = Profile_ReadString$(Sect$, key$, D$)
  579.  
  580.     Select Case UCase$(S$)
  581.         Case "Y", "TRUE", "YES", "1"
  582.             Profile_ReadBool = True
  583.         Case Else
  584.             Profile_ReadBool = False
  585.     End Select
  586.  
  587. End Function
  588.  
  589. Function Profile_ReadInt(Sect$, key$, Def%) As Integer
  590.     Profile_ReadInt = GetPrivateProfileInt(Sect$, key$, Def%, App_Profile)
  591. End Function
  592.  
  593. Function Profile_ReadString$(Sect$, key$, Def$)
  594.     Dim S$, r%
  595.     
  596.     S$ = Space$(100)                        ' prepare an empty buffer space
  597.     r% = GetPrivateProfileString(Sect$, key$, Def$, S$, 100, App_Profile)
  598.     Profile_ReadString$ = StringTrim(S$)    ' remove excess spaces
  599.  
  600. End Function
  601.  
  602. Sub Profile_WriteBool(Sect$, key$, I%)
  603.     
  604.     If I% Then
  605.         Profile_WriteString Sect$, key$, "yes"
  606.     Else
  607.         Profile_WriteString Sect$, key$, "no"
  608.     End If
  609. End Sub
  610.  
  611. Sub Profile_WriteInt(Sect$, key$, I%)
  612.     Profile_WriteString Sect$, key$, Format$(I%)
  613. End Sub
  614.  
  615. Sub Profile_WriteString(Sect$, key$, What$)
  616.     Dim r%
  617.     
  618.     r% = WritePrivateProfileString(Sect$, key$, What$, App_Profile)
  619.  
  620. End Sub
  621.  
  622. '
  623. '
  624. Sub RecentFile_AddItem(f As Form, fname$)
  625.     
  626.     Dim I%, Slot%
  627.     Dim r As Control, S$
  628.  
  629.     ' Do this only if file is different from the most recent one
  630.     If fname$ = RecentFile_Item$(f, 1) Then Exit Sub
  631.  
  632.     ' Make sure the separator line before names is visible
  633.     f.FileRecent(0).Visible = True
  634.     
  635.     ' Remove file from the list if already there before adding to top
  636.     For Slot% = 1 To 3                  ' last slot (4) would be discarded anyway
  637.         S$ = RecentFile_Item$(f, I%)
  638.         If S$ = fname$ Then Exit For    ' Will shift list only this far
  639.     Next Slot%
  640.     
  641.  
  642.     ' Shift down the list. Make sure the shifted down items are visible
  643.     For I% = Slot% To 2 Step -1
  644.         
  645.         S$ = RecentFile_Item(f, I% - 1)
  646.         
  647.         If S$ <> "" Then
  648.             f.FileRecent(I%).Caption = RecentFile_Format$(S$, I%)
  649.             f.FileRecent(I%).Visible = True
  650.         End If
  651.     
  652.     Next I%
  653.     
  654.     
  655.     ' Finally, set the name to the top slot.
  656.     Set r = f.FileRecent(1)
  657.     r.Caption = RecentFile_Format$(fname$, 1)
  658.     r.Visible = True
  659.  
  660. End Sub
  661.  
  662. Function RecentFile_Format$(fname$, I%)
  663.     RecentFile_Format = "&" & Trim$(Str$(I%)) & " " & fname$
  664. End Function
  665.  
  666. Function RecentFile_Item$(f As Form, I%)
  667.     RecentFile_Item$ = Mid$(f.FileRecent(I%).Caption, 4)
  668. End Function
  669.  
  670. '
  671. ' Read recent file entry from profile, if any add it to the
  672. ' menu with a number tag and make sure that the separator is
  673. ' visible
  674. '
  675. Sub RecentFile_Read(f As Form)
  676.     Dim I%, S$
  677.  
  678.     For I% = 1 To 4
  679.         S$ = Profile_ReadString$(SEC_GLOBAL, "RecentFile" & Trim$(Str$(I%)), "")
  680.  
  681.         If S$ <> "" Then
  682.             f.FileRecent(I%).Caption = RecentFile_Format$(S$, I%)
  683.             f.FileRecent(I%).Visible = True
  684.             
  685.             ' lines before the list of files
  686.             f.FileRecent(0).Visible = True
  687.             
  688.         End If
  689.     Next I%
  690.  
  691. End Sub
  692.  
  693. Sub RecentFile_Write(f As Form)
  694.     Dim I%
  695.     
  696.     For I% = 1 To 4
  697.         Profile_WriteString SEC_GLOBAL, "RecentFile" & Trim$(Str$(I%)), RecentFile_Item(f, I%)
  698.     Next I%
  699.  
  700. End Sub
  701.  
  702. '
  703. ' Replace in string S every occurrence of characters from
  704. ' character set CSet with RStr string.
  705. '
  706. ' This function is a more general solution to the problem
  707. ' where you want the user to input names and data in free
  708. ' format and then automatically replace illegal characters
  709. ' (i.e. substitute underscores for blanks).
  710. '
  711. ' Returns the converted string.
  712. '
  713. ' Example: Replace$("abc abc", "bc", "_") --> "a__ a__"
  714. '
  715. Function Replace$(S As String, CSet As String, RStr As String)
  716.     Dim r As String
  717.     Dim I As Integer, L As Integer
  718.  
  719.     r = S
  720.     L = Len(r)
  721.     
  722.     For I = 1 To L
  723.         If IsInCharSet(Mid$(r, I, 1), CSet) = True Then
  724.              r = Left$(r, I - 1) & RStr & Mid$(r, I + 1)
  725.         End If
  726.     Next I
  727.  
  728.     Replace$ = r
  729.  
  730. End Function
  731.  
  732. '
  733. ' This function prompts the user with a modal dialog
  734. ' showing the title of the application, the passed
  735. ' message, and a STOP icon.
  736. '
  737. ' If the global VB variable 'Err' is set due to
  738. ' a real VB run-time error, the corresponding message
  739. ' is appended to the passed message and also shown
  740. ' in the dialog.
  741. '
  742. Sub ReportError(Msg$)
  743.     Dim S As String, LF As String
  744.     
  745.     LF = Chr$(10)
  746.  
  747.     S = "Error!" & LF & LF & Msg$
  748.     If Err > 0 Then
  749.         S = S & LF & LF & "Reason:  " & Error$
  750.     End If
  751.  
  752.     MsgBox S, MB_ICONSTOP, App.Title
  753. End Sub
  754.  
  755. Function StringTrim(Str1 As String) As String
  756.     Dim S$
  757.  
  758.     S$ = Trim$(Str1)
  759.  
  760.     If Right$(S$, 1) = Chr$(0) Then
  761.         S$ = Left$(S$, Len(S$) - 1)
  762.     End If
  763.  
  764.     S$ = Trim$(S$)
  765.  
  766.     StringTrim = S$
  767.  
  768. End Function
  769.  
  770. '
  771. ' Strip passed string of leading and trailing blanks.
  772. '
  773. ' Blanks are defined as the characters in set BSet
  774. '
  775. Function Strip$(S As String, BSet As String)
  776.     Dim r As String
  777.     Dim I As Integer, L As Integer
  778.     
  779.     r = S
  780.     L = Len(r)
  781.     
  782.     
  783.     ' Loop until a non-blank char is found
  784.     For I = 1 To L
  785.         If IsInCharSet(Mid$(r, I, 1), BSet) = False Then Exit For
  786.     Next I
  787.  
  788.     ' If any blanks were found, keep right part of string.
  789.     If I > 1 Then r = Mid$(r, I)
  790.  
  791.     L = Len(r)
  792.     
  793.     For I = L To 1 Step -1
  794.         If IsInCharSet(Mid$(r, I, 1), BSet) = False Then Exit For
  795.     Next I
  796.     
  797.     If I < L Then r = Left$(r, I)
  798.  
  799.     Strip$ = r
  800.  
  801. End Function
  802.  
  803.